iT邦幫忙

2026 iThome 鐵人賽

DAY 8
0
Software Development

從 Laravel 到 Spring Boot:30 天打造縮網址服務系列 第 8

Day8 - 資料庫遷移 Flyway/Liquibase vs Laravel Migration

  • 分享至 

  • xImage
  •  

Flyway vs Liquibase,這系列選哪個

Java 生態系常見的 migration 工具主要兩個:

  • Flyway:直接寫原生 SQL,檔名照嚴格規則命名,機制單純
  • Liquibase:用 XML/YAML/JSON 描述 schema 變更,多一層抽象,換資料庫引擎時更方便,但學習成本也更高

這系列選 Flyway——理由跟之前選 Maven 不選 Gradle 一樣:現在還在建立基本功,Flyway「檔名照規則命名、內容就是純 SQL」這種「看得到就是全部」的簡單心智模型,比 Liquibase 那層額外的 DSL 抽象更適合現在的階段。

Laravel Migration vs Flyway:怎麼定義一張表

Laravel 用 PHP DSL 描述 schema,實際的 SQL 由 Laravel 幫你組出來:

Schema::create('links', function (Blueprint $table) {
    $table->id();
    $table->string('code')->unique();
    $table->string('original_url');
    $table->unsignedBigInteger('owner_id');
    $table->integer('click_count')->default(0);
    $table->timestamp('expires_at')->nullable();
    $table->timestamp('created_at')->nullable();
});

Flyway 沒有這層 DSL,檔案內容就是純 SQL,檔名放在 src/main/resources/db/migration/

-- V1__create_links_table.sql
CREATE TABLE links (
    id BIGINT AUTO_INCREMENT PRIMARY KEY,
    code VARCHAR(255) NOT NULL UNIQUE,
    original_url VARCHAR(2048) NOT NULL,
    owner_id BIGINT NOT NULL,
    click_count INT NOT NULL DEFAULT 0,
    expires_at TIMESTAMP NULL,
    created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
);

好處是完全不用學一套新的 DSL 語法,寫的就是真的會被執行的 SQL;代價是換資料庫引擎(例如 MySQL 換 PostgreSQL)時,SQL 語法可能要跟著改,不像 Laravel Schema Builder 有一層抽象幫忙處理跨資料庫的語法差異。

版本追蹤:時間戳記 vs 嚴格版本號

Laravel 的 migration 檔名長這樣:2026_09_22_000001_create_links_table.php,靠時間戳記排序,框架在 migrations 資料表記錄「哪些檔案已經跑過」。

Flyway 也有一張類似的追蹤表 flyway_schema_history,但檔名規則更嚴格:必須是 V{版本號}__{描述}.sql 這個格式,版本號決定執行順序(V1V2V2.1⋯),檔名一旦跑過就不能再改內容——Flyway 會對每個檔案算 checksum,內容被改過會直接讓下次啟動失敗,逼你「已經跑過的 migration 就是歷史事實,不能偷改」,這點比 Laravel 的慣例更強制。

心態轉換:只能往前修,不能往後退

Laravel 的 migration 檔案有 up()down()php artisan migrate:rollback 可以照 down() 復原上一次的變更。

Flyway 社群版沒有這個功能——沒有 down migration 這回事,schema 改錯了,正確做法是再寫一個新的 migration 去修正它,而不是復原上一個檔案(真正的復原/回滾是付費的 Flyway Teams 版才有)。這是刻意的設計哲學:migration 歷史是不可變的紀錄,就像 git commit 一樣,修正錯誤用新的 commit,不會去改寫歷史。剛從 Laravel 過來會不太習慣,但換個角度想,這其實跟這系列前面提過的「Spring Boot 4 的破壞性變更只能往前接受,不能回頭假裝沒發生」是同一種心態。

接回 Day07:關掉 Hibernate 自動建表

Day07 提到「先讓 Hibernate 自動建表」,那是靠 application.yml 裡的 ddl-auto: update 做到的——開發階段很方便,但正式導入 Flyway 之後,兩邊同時想管 schema 會打架。正確做法是把 Hibernate 的角色改成「只負責檢查」,不再自己動手改:

spring:
  jpa:
    hibernate:
      ddl-auto: validate   # 只驗證 Entity 跟 schema 對不對得上,不會自動改
  flyway:
    enabled: true
    locations: classpath:db/migration

pom.xml 也要加上 Flyway 的依賴(記得回顧 Day03:Maven 的依賴要自己宣告,不像有些工具是內建的):

<dependency>
    <groupId>org.flywaydb</groupId>
    <artifactId>flyway-core</artifactId>
</dependency>

這樣一來,schema 的真相只有一個來源(Flyway 的 migration 檔案),Hibernate 退回它該做的事——確認程式碼裡的 Entity 定義跟資料庫實際的 schema 沒有兜不起來,兩邊職責清楚分開,不再互搶。


上一篇
Day7 - Spring Data JPA vs Eloquent ORM 基礎
下一篇
Day9 - 層架構與 DTO/Mapper(縮網址核心 API 雛形)
系列文
從 Laravel 到 Spring Boot:30 天打造縮網址服務9
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言